checkout: Support --union-identical and --force-copy{,--zerosized}
authorColin Walters <walters@verbum.org>
Thu, 11 Oct 2018 18:35:23 +0000 (14:35 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Thu, 11 Oct 2018 20:49:54 +0000 (20:49 +0000)
Actually testing the patch to add `--force-copy-zerosized` to
rpm-ostree tripped over the fact that it uses `--union-identical`,
and we just hit an assertion failure with that combination.

Fix this by copying over the logic we have for the hardlink case.

Closes: #1753
Approved by: jlebon

src/libostree/ostree-repo-checkout.c
tests/basic-test.sh

index fcae6a7f77feea5114f9db0be48cb798ccc0051a..5ae799231c772ed3b2da6e0f59501076752347ab 100644 (file)
@@ -196,6 +196,7 @@ static gboolean
 create_file_copy_from_input_at (OstreeRepo     *repo,
                                 OstreeRepoCheckoutAtOptions  *options,
                                 CheckoutState  *state,
+                                const char     *checksum,
                                 GFileInfo      *file_info,
                                 GVariant       *xattrs,
                                 GInputStream   *input,
@@ -358,8 +359,35 @@ create_file_copy_from_input_at (OstreeRepo     *repo,
           replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST;
           break;
         case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL:
-          /* We don't support copying in union identical */
-          g_assert_not_reached ();
+          {
+            replace_mode = GLNX_LINK_TMPFILE_NOREPLACE;
+            struct stat dest_stbuf;
+            if (!glnx_fstatat_allow_noent (destination_dfd, destination_name, &dest_stbuf,
+                                           AT_SYMLINK_NOFOLLOW, error))
+              return FALSE;
+            if (errno == 0)
+              {
+                /* We do a checksum comparison; see also equivalent code in
+                 * checkout_file_hardlink().
+                 */
+                OstreeChecksumFlags flags = 0;
+                if (repo->disable_xattrs)
+                  flags |= OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS;
+
+                g_autofree char *actual_checksum = NULL;
+                if (!ostree_checksum_file_at (destination_dfd, destination_name,
+                                              &dest_stbuf, OSTREE_OBJECT_TYPE_FILE,
+                                              flags, &actual_checksum, cancellable, error))
+                  return FALSE;
+
+                if (g_str_equal (checksum, actual_checksum))
+                  return TRUE;
+
+                /* Otherwise, fall through and do the link, we should
+                 * get EEXIST.
+                 */
+              }
+          }
           break;
         }
 
@@ -773,7 +801,7 @@ checkout_one_file_at (OstreeRepo                        *repo,
                                   cancellable, error))
         return FALSE;
 
-      if (!create_file_copy_from_input_at (repo, options, state, source_info, xattrs, input,
+      if (!create_file_copy_from_input_at (repo, options, state, checksum, source_info, xattrs, input,
                                            destination_dfd, destination_name,
                                            cancellable, error))
         return glnx_prefix_error (error, "Copy checkout of %s to %s", checksum, destination_name);
index a817b9d152864eb8f739a59d96c14e3054190a97..3c4823d747c9eb22c1fd3df4207a11d3251b2e0c 100644 (file)
@@ -21,7 +21,7 @@
 
 set -euo pipefail
 
-echo "1..$((84 + ${extra_basic_tests:-0}))"
+echo "1..$((85 + ${extra_basic_tests:-0}))"
 
 CHECKOUT_U_ARG=""
 CHECKOUT_H_ARGS="-H"
@@ -709,6 +709,20 @@ assert_files_hardlinked tree-with-empty-files/an{,other}emptyfile
 rm tree-with-empty-files -rf
 echo "ok checkout --force-copy-zerosized"
 
+# These should merge, they're identical
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files
+echo notempty > tree-with-empty-files/anemptyfile.new && mv tree-with-empty-files/anemptyfile{.new,}
+$CMD_PREFIX ostree --repo=repo commit --consume -b tree-with-conflicting-empty-files --tree=dir=tree-with-empty-files
+# Reset back to base
+rm tree-with-empty-files -rf
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files
+if $CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-conflicting-empty-files tree-with-empty-files 2>err.txt; then
+    fatal "--union-identical --force-copy-zerosized unexpectedly succeeded with non-identical files"
+fi
+assert_file_has_content err.txt 'error:.*File exists'
+echo "ok checkout --union-identical --force-copy-zerosized"
+
 cd ${test_tmpdir}
 rm files -rf && mkdir files
 mkdir files/worldwritable-dir